package com.media.entrance.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class RedisService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    private final long lockExpireTime = 30 * 1000; // 锁过期时间

    public RedisService(StringRedisTemplate stringRedisTemplate) {
        this.redisTemplate = stringRedisTemplate;
    }

    // redis加锁
    public boolean lock(String key) {
        Boolean result = redisTemplate.opsForValue().setIfAbsent(key, "locked", lockExpireTime, TimeUnit.MILLISECONDS);
        return result != null && result;
    }

    // redis解锁
    public void unlock(String key) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(key), "locked");
    }
    /**
     * 设置指定的key的value
     *
     * @param key 关键字
     * @param result value值
     * @param timeoutSeconds 有效时间，0为一直有效
     */
    public void setValue(String key, String result, int timeoutSeconds){
        redisTemplate.opsForValue().set(key, result);
        if (timeoutSeconds > 0) {
            redisTemplate.expire(key, timeoutSeconds, TimeUnit.SECONDS);
        }
    }

    /**
     * 获取指定的key的value
     *
     * @param key 关键字
     * @return String 获取字符对象
     */
    public String getValue(String key) {
        Boolean haskey;
        try {
            haskey = redisTemplate.hasKey(key);
        } catch (NullPointerException e) {
            log.error("[matchService.getValue] [error]", e);
            return null;
        }
        return (Boolean.TRUE.equals(haskey)) ? redisTemplate.opsForValue().get(key) : null;
    }

    /**
     * 清理指定的key的value
     *
     * @param key 关键字
     * @return 清理成功为true
     */
    public Boolean clearValue(String key) {
        Boolean haskey;
        try {
            haskey = redisTemplate.hasKey(key);
            if (Boolean.TRUE.equals(haskey)) {
                return redisTemplate.delete(key);
            }
        } catch (NullPointerException e) {
            log.error("[matchService.clearValue] [error]", e);
        }
        return false;
    }

    /**
     * 增加有序集合
     *
     * @param key 关键字
     * @param value 内容
     * @param seqNo 排序分数
     * @return key和value和seqNo存在新增失败，返回false；仅seqNo不同则更新，不存在新增成功，返回true。
     */
    public Boolean addZset(String key, Object value, double seqNo) {
        try {
            return redisTemplate.opsForZSet().add(key, (String) value, seqNo);
        } catch (Exception e) {
            log.error("[matchService.addZset] [error]", e);
            return false;
        }
    }

    /**
     * 根据key和value移除指定元素
     *
     * @param key 关键字
     * @param value 内容
     * @return 未查询到对应的key和value，返回0，否则返回1
     */
    public Long removeZset(String key, Object value) {
        return redisTemplate.opsForZSet().remove(key, value);
    }

    /**
     * 排名ZSET
     *
     * @param key 关键字
     * @param obj 对应的内容
     * @return long 在队列中的位置
     */
    public long rankZset(String key, Object obj) {
        try {
            return redisTemplate.opsForZSet().rank(key, obj);
        } catch (Exception e) {
            return -1;
        }

    }

    /**
     * 获取zset集合数量
     *
     * @param key 关键字
     * @return key不存在，返回0；存在，返回集合的个数。
     */
    public Long countZset(String key) {
        try {
            return redisTemplate.opsForZSet().size(key);
        } catch (Exception e) {
            log.error("[matchService.countZset] [error] [key is {}]", key, e);
            return 0L;
        }
    }

    /**
     * 获取zset指定范围内的集合
     *
     * @param key 关键字
     * @param start 开始的范围
     * @param end 结束的范围 -1为全部
     * @return Set集合
     */
    public Set<String> rangeZset(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().range(key, start, end);
        } catch (Exception e) {
            log.error("[RedisUtils.rangeZset] [error] [key is {},start is {},end is {}]", key, start, end, e);
            return null;
        }
    }

    /**
     * 删除zset指定范围内的集合
     *
     * @param key 关键字
     * @param start 开始的范围
     * @param end 结束的范围 -1为全部
     * @return 个数
     */
    public long removeZSetRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().removeRange(key, start, end);
        } catch (Exception e) {
            log.error("[RedisUtils.removeRange] [error] [key is {},start is {},end is {}]", key, start, end, e);
            return -1;
        }
    }
}
